<?php
namespace app\services;

use app\admin\controller\ApiCommon;
use app\crm\logic\WhereLogic;
use app\crm\model\Customer;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Db;

// 发送短信
class SendMsg
{
    // 配置参数
    protected $softwareSerialNo = 'HBSDK-21FE5JCWON';
    protected $serialpass = '315295';
    protected $key = 'xinyi';
    protected $primaryUrl = 'http://ws.vitions.com:8080/sdk/SDKService?wsdl';
    protected $secondaryUrl = 'http://ws.hdwinfo.cn:8080/sdk/SDKService?wsdl';
    
    // 错误码映射
    protected $errorCodes = [
        0 => '短信发送成功',
        -1 => '系统异常',
        -2 => '客户端异常',
        -117 => '发送短信失败',
        -120 => '修改密码失败',
        -122 => '号码注销激活失败',
        -124 => '查询余额失败',
        -127 => '计费失败0余额',
        -128 => '计费失败余额不足',
        -190 => '数据操作失败',
        -1100 => '序列号错误,序列号不存在内存中,或尝试攻击的用户',
        -1102 => '序列号密码错误',
        -1103 => '序列号Key错误',
        -1104 => '路由失败，请联系系统管理员',
        -1105 => '注册号状态异常, 未用 1',
        -1107 => '注册号状态异常, 停用 3',
        -1108 => '注册号状态异常, 停止 5',
        -1131 => '充值卡无效',
        -1132 => '充值密码无效',
        -1133 => '充值卡绑定异常',
        -1134 => '充值状态无效',
        -1135 => '充值金额无效',
        -1901 => '数据库插入操作失败',
        -1902 => '数据库更新操作失败',
        -1903 => '数据库删除操作失败',
        -9000 => '数据格式错误,数据超出数据库允许范围',
        -9001 => '序列号格式错误',
        -9002 => '密码格式错误',
        -9003 => '客户端Key格式错误',
        -9004 => '设置转发格式错误',
        -9005 => '公司地址格式错误',
        -9006 => '企业中文名格式错误',
        -9007 => '企业中文名简称格式错误',
        -9008 => '邮件地址格式错误',
        -9009 => '企业英文名格式错误',
        -9010 => '企业英文名简称格式错误',
        -9011 => '传真格式错误',
        -9012 => '联系人格式错误',
        -9013 => '联系电话格式错误',
        -9014 => '邮编格式错误',
        -9015 => '新密码格式错误',
        -9016 => '发送短信包大小超出范围',
        -9017 => '发送短信内容格式错误',
        -9018 => '发送短信扩展号格式错误',
        -9019 => '发送短信优先级格式错误',
        -9020 => '发送短信手机号格式错误',
        -9021 => '发送短信定时时间格式错误',
        -9022 => '发送短信唯一序列值错误',
        -9023 => '充值卡号格式错误',
        -9024 => '充值密码格式错误',
        -9025 => '客户端请求sdk5超时'
    ];
    
    
    /**
     * 创建SOAP客户端并调用指定方法
     * 
     * @param string $method 调用的方法名
     * @param array $params 方法参数
     * @return mixed 调用结果
     * @throws SoapFault SOAP调用异常
     */
    protected function callSoapMethod(string $method, array $params)
    {
        try {
            $client = new \SoapClient($this->primaryUrl);
            return $client->$method($params);
        }catch (SoapFault $e)
        {
            // 主服务失败时尝试备用服务
            try
            {
                $client = new \SoapClient($this->secondaryUrl);
                return $client->$method($params);
            } catch (SoapFault $e)
            {
                throw new SoapFault("SOAP", "主备服务均不可用: {$e->getMessage()}");
            }
        }
    }

    /**
     * 注册序列号到短信平台
     * 
     * @return array 执行结果 [
     *     'code' => 状态码,
     *     'msg'  => 状态描述
     * ]
     */
    public function registEx(): array
    {
        $params = [
            'arg0' => $this->softwareSerialNo,
            'arg1' => $this->key,
            'arg2' => $this->serialpass,
        ];
        
        try {
            $result = $this->callSoapMethod('registEx', $params);
            $responseCode = $result->return ?? -1;
            
            if ($responseCode == 0) {
                return ['code' => 200, 'msg' => "序列号注册成功"];
            }
            return ['code' => $responseCode,'msg'  => $this->errorCodes[$responseCode] ?? "未知错误"];
        } catch (SoapFault $e)
        {
            return ['code' => -2, 'msg' => "SOAP调用失败: {$e->getMessage()}"];
        }
    }

    /**
     * 查询短信账户余额
     * 
     * @return array 查询结果 [
     *     'code' => 状态码,
     *     'data' => 余额数值,
     *     'msg'  => 状态描述
     * ]
     */
    public function getBalance(): array
    {
        $params = [
            'arg0' => $this->softwareSerialNo,
            'arg1' => $this->key,
        ];
        
        try {
            $result = $this->callSoapMethod('getBalance', $params);
            $balance = $result->return ?? -1;
            
            return [
                'code' => 200,
                'data' => $balance,
                'msg'  => "余额查询成功"
            ];
        } catch (SoapFault $e) {
            return [
                'code' => -124,
                'data' => 0,
                'msg'  => "余额查询失败: {$e->getMessage()}"
            ];
        }
    }
    
    
//----------------------------------------------------------------------------------------------------------------


    // 单发短信
    public function sendSMS(array $data,string $sendTime = '',string $addSerial = '',string $srcCharset = 'GBK',int $smsPriority = 5,int $smsID = 0): array 
    {
        // 从数据数组中提取手机号和短信内容
        $mobile = $data['telephone'] ?? '';
        $smsContent = $data['content'] ?? '';
        
        // 验证必要字段是否存在
        if (empty($mobile) || empty($smsContent)) {
            return ['code' => -100, 'msg' => '缺少手机号或短信内容'];
        }
        
        // 调用私有发送方法
        return $this->sendSingleSMS(
            $mobile,
            $smsContent,
            $data,
            $sendTime,
            $addSerial,
            $srcCharset,
            $smsPriority,
            $smsID
        );
    }
    
    
    
    // 群发短信
    public function sendBatchSMS(array $dataList,string $sendTime = '',string $addSerial = '',string $srcCharset = 'GBK',int $smsPriority = 5,int $smsID = 0): array 
    {
        $successCount = 0;
        $failCount = 0;
        $errorMessages = [];
        $createTime = time();
    
        foreach ($dataList as $data)
        {
            // 从每条数据中提取手机号和短信内容
            $mobile = $data['telephone'] ?? '';
            $smsContent = $data['content'] ?? '';
            
            // 验证必要字段
            if (empty($mobile) || empty($smsContent)) {
                $failCount++;
                $errorMessages[] = "缺少手机号或短信内容";
                continue;
            }
    
            $result = $this->sendSingleSMS(
                $mobile,
                $smsContent,
                $data,
                $sendTime,
                $addSerial,
                $srcCharset,
                $smsPriority,
                $smsID,
                $createTime
            );
    
            if ($result['code'] === 200)
            {
                $successCount++;
            }else
            {
                $failCount++;
                $errorMessages[] = "{$mobile}: {$result['msg']}";
            }
        }
    
        // 生成最终结果消息
        $total = count($dataList);
        if ($successCount === $total)
        {
            return ['code' => 200, 'msg' => "全部短信发送成功 ({$successCount}条)"];
        } elseif ($failCount === $total)
        {
            return ['code' => -117, 'msg' => "全部短信发送失败: " . implode('; ', $errorMessages)];
        }else
        {
            $msg = "部分短信发送成功: {$successCount}成功, {$failCount}失败. ";
            $msg .= "失败详情: " . implode('; ', $errorMessages);
            return ['code' => 207, 'msg' => $msg];
        }
    }
    
    /**
     * 发送短信
     * 
     * @param string|array $mobile      手机号(单个字符串或多个号码数组)
     * @param string $smsContent       短信内容
     * @param array $data              关联数据
     * @param string $sendTime         定时发送时间(YmdHis格式，空字符串表示即时发送)
     * @param string $addSerial        扩展号码(默认空)
     * @param string $srcCharset       字符编码(默认GBK)
     * @param int $smsPriority         短信优先级(1-5，默认5)
     * @param int $smsID               短信ID(必须唯一，0表示不需要状态报告)
     * @return array 发送结果 [
     *     'code' => 状态码,
     *     'msg'  => 状态描述
     * ]
     */
    private function sendSingleSMS(string $mobile,string $smsContent,array $data,string $sendTime,string $addSerial,string $srcCharset,int $smsPriority,int $smsID,int $createTime = null): array 
    {
        $trimmedNumber = trim($mobile);
        $createTime = $createTime ?? time();
    
        // 验证手机号格式
        if (!preg_match('/^1[3-9]\d{9}$/', $trimmedNumber))
        {
            $this->logSmsRecord($trimmedNumber, $smsContent, $data, 2, "无效手机号格式", $createTime);
            return ['code' => -1, 'msg' => "无效手机号格式"];
        }
    
        $params = [
            'arg0' => $this->softwareSerialNo,
            'arg1' => $this->key,
            'arg2' => $sendTime,
            'arg3' => $trimmedNumber,
            'arg4' => $smsContent,
            'arg5' => $addSerial,
            'arg6' => $srcCharset,
            'arg7' => (string)$smsPriority,
            'arg8' => (string)$smsID
        ];
    
        try {
            $result = $this->callSoapMethod('sendSMS', $params);
            $responseCode = $result->return ?? -1;
    
            if ($responseCode == 0)
            {
                $this->logSmsRecord($trimmedNumber, $smsContent, $data, 1, null, $createTime);
                return ['code' => 200, 'msg' => "发送成功"];
            }else
            {
                $errorMsg = $this->errorCodes[$responseCode] ?? "未知错误";
                $this->logSmsRecord($trimmedNumber, $smsContent, $data, 2, $errorMsg, $createTime);
                return ['code' => $responseCode, 'msg' => $errorMsg];
            }
        }catch (SoapFault $e)
        {
            $errorMsg = "短信发送失败: {$e->getMessage()}";
            $this->logSmsRecord($trimmedNumber, $smsContent, $data, 2, $errorMsg, $createTime);
            return ['code' => -999, 'msg' => $errorMsg];
        }
    }
    

    /**
     * 统一记录短信日志
     * 
     * @param string $number      手机号码
     * @param string $content     短信内容
     * @param array $data         关联数据
     * @param int $status         发送状态(1=成功, 2=失败)
     * @param string|null $errorMsg 错误信息
     * @param int $createTime     创建时间戳
     */
    private function logSmsRecord(string $number, string $content, array $data, int $status, ?string $errorMsg = null, int $createTime)
    {
        $logData = [
            'market_id'    => $data['market_id'] ?? 0,
            'shop_id'      => $data['shop_id'] ?? 0,
            'customer_id'  => $data['customer_id'] ?? 0,
            'telephone'    => $number,
            'content'      => $content,
            'type'         => $data['type'] ?? 1,
            'status'       => $status,
            'error_msg'    => $errorMsg,
            'create_time'  => $createTime,
            'order_id'     => $data['order_id'] ?? null,
            'order_type'   => $data['order_type'] ?? null,
            'expend_money' => $data['expend_money'] ?? 0.00,
            'surplus_money'=> $data['surplus_money'] ?? 0.00
        ];
        
        DB::name('customer_send')->insert($logData);
    }
     
     
    
    

}
